﻿using Newtonsoft.Json.Linq;
using RazorEngineCore;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using static Npgsql.Replication.PgOutput.Messages.RelationMessage;
using static System.Runtime.InteropServices.Marshalling.IIUnknownCacheStrategy;

namespace CodeGenerate.Model
{
    public class ViewModel
    {
        SqlSugarClient db;
        string connstr;

        public ViewModel(string connstr)
        {
            this.connstr = connstr;
        }

        string ShareEntityTemplatePath = "ShareEntity.cshtml";
        string ServerEntityTemplatePath = "ServerEntity.cshtml";
        string ServerDaoTemplatePath = "ServerDao.cshtml";
        string ServerBllTemplatePath = "ServerBll.cshtml";
        string ServerControllerTemplatePath = "ServerController.cshtml";
        string ClientDaoTemplatePath = "ClientDao.cshtml";


        public bool RewriteShareEntity { get; set; } = true;
        public bool RewriteServerEntity { get; set; } = true;
        public bool RewriteServerDao { get; set; } = true;
        public bool RewriteServerBll { get; set; } = true;
        public bool RewriteServerController { get; set; } = true;
        public bool RewriteClientDao { get; set; } = true;


        public string ShareEntityPath { get; set; } = "";
        public string ServerEntityPath { get; set; } = "";
        public string ServerDaoPath { get; set; } = "";
        public string ServerBllPath { get; set; } = "";
        public string ServerControllerPath { get; set; } = "";
        public string ClientDaoPath { get; set; } = "";

        public string ShareEntityNamespace { get; set; } = "";
        public string ServerEntityNamespace { get; set; } = "";
        public string ServerDaoNamespace { get; set; } = "";
        public string ServerBllNamespace { get; set; } = "";
        public string ServerControllerNamespace { get; set; } = "";
        public string ClientDaoNamespace { get; set; } = "";


        /// <summary>
        /// 子级目录
        /// </summary>
        public string SonPath { get; set; } = "";

        /// <summary>
        /// 父类类型
        /// </summary>
        public PEnum PClass { get; set; }

        /// <summary>
        /// 表相关信息
        /// </summary>
        public CodeTable TableInfo { get; set; }

        private List<string> getIgnoreColumn()
        {
            List<string> re = [];

            switch (PClass)
            {
                case PEnum.ContainDate:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");
                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");
                        break;

                    }
                case PEnum.ContainTitle:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("title");
                        re.Add("remarks");
                        break;
                    }

                case PEnum.ContainTitleRepair:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("title");
                        re.Add("remarks");

                        re.Add("repair_method");
                        re.Add("repair_target_id");
                        re.Add("version_id");
                        break;
                    }
                case PEnum.Base:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");
                        break;
                    }
                case PEnum.MiddleTable:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("accepter_id");
                        re.Add("goods_id");
                        break;
                    }
                case PEnum.RepairMiddleTable:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("accepter_id");
                        re.Add("goods_id");

                        re.Add("repair_method");
                        re.Add("repair_target_id");
                        re.Add("version_id");
                        break;
                    }
                case PEnum.Repair:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("repair_method");
                        re.Add("repair_target_id");
                        re.Add("version_id");
                        break;
                    }
                case PEnum.Tree:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("title");
                        re.Add("remarks");

                        re.Add("sort");
                        re.Add("the_code");
                        re.Add("tree_parent_id");
                        re.Add("tree_root_id");
                        break;
                    }
                case PEnum.TreeRepair:
                    {
                        re.Add("id");
                        re.Add("state");
                        re.Add("is_delete");

                        re.Add("create_time");
                        re.Add("creator");
                        re.Add("update_time");
                        re.Add("updater");

                        re.Add("title");
                        re.Add("remarks");

                        re.Add("sort");
                        re.Add("the_code");
                        re.Add("tree_parent_id");
                        re.Add("tree_root_id");

                        re.Add("repair_method");
                        re.Add("repair_target_id");
                        re.Add("version_id");
                        break;
                    }
            }

            return re;
        }

        public List<CodeColumns> Columns
        {
            get
            {
                List<CodeColumns> re = [];
                var ignore = getIgnoreColumn();

                foreach (var column in TableInfo.Columns)
                {
                    if (ignore.Contains(column.DbColumnName)) continue;

                    re.Add(column);
                }

                return re;
            }
        }

        public string SerialNumber
        {
            get
            {
                string re = "";

                switch (PClass)
                {
                    case PEnum.ContainDate:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.ContainTitle:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }

                    case PEnum.ContainTitleRepair:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.Base:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.MiddleTable:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.RepairMiddleTable:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.Repair:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.Tree:
                        {
                            re = "100<SerialNumber<200";
                            break;
                        }
                    case PEnum.TreeRepair:
                        {
                            re = "500<SerialNumber<600";
                            break;
                        }
                }

                return re;
            }
        }


        public SqlSugarClient GetDb()
        {

            if (this.db == null)
            {

                db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = connstr,
                    DbType = DbType.MySql,
                    InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息
                    IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样我就不多解释了
                    ConfigureExternalServices = new ConfigureExternalServices()
                    {
                        EntityNameService = (type, entity) =>
                        {
                            if (type.Name.EndsWith("Entity"))
                            {
                                entity.DbTableName = type.Name[..^6];
                                entity.DbTableName = entity.DbTableName.ToLower();
                            }
                        },
                        EntityService = (t, column) =>
                        {
                            //var a = t.GetCustomAttributes<DbInfoAttribute>().FirstOrDefault();
                            //if (a != default)
                            //{
                            //    if (a.IsPrimaryKey)
                            //    {
                            //        column.IsPrimarykey = true;
                            //    }

                            //    if (a.IsIgnore)
                            //    {
                            //        column.IsIgnore = true;
                            //    }

                            //    if (!string.IsNullOrEmpty(a.ColumnDataType))
                            //    {
                            //        column.DataType = a.ColumnDataType;
                            //    }
                            //    if (a.Length > 0)
                            //    {
                            //        column.Length = a.Length;
                            //    }

                            //}

                            /*
                            string colName = column.PropertyName.ToLower();

                            if (colName == "id") //是id的设为主键
                            {
                                column.IsPrimarykey = true;
                                //if (column.PropertyInfo.PropertyType == typeof(int)) //是id并且是int的是自增
                                //{
                                //    column.IsIdentity = true;
                                //}
                            }
                            if (colName == "scopetargetname" || colName == "updatername" || colName == "creatorname")
                            {
                                column.IsIgnore = true;
                            }
                            */
                        }
                    }
                });

                db.Aop.OnLogExecuting = (sql, pars) =>
                {
#if DEBUG
                    Console.WriteLine(sql);
                    // ServerContext.Obj.Log.Info(sql + "\r\n" +
                    // db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
#endif
                };
                db.Aop.OnLogExecuted = (sql, pars) => //SQL执行完
                {
#if DEBUG

                    //  ServerContext.Obj.Log.Info(db.Ado.SqlExecutionTime.ToString());//输出SQL执行时间
#endif
                };
                db.Aop.OnError = (exp) =>//SQL报错
                {
                    // ServerContext.Obj.Log.Error(db.Ado.SqlExecutionTime.ToString());//输出SQL执行时间         
                };

            }

            return db;
        }


        public void Gen(string sheetName)
        {
            TableInfo = CodeTable.GetTableInfo(sheetName, GetDb());

            GenShareEntity();
            //ServerEntity();
            ServerDao();
            ServerBll();
            ServerController();
            ClientDao();
        }


        private void GenShareEntity()
        {
            string savePath = ShareEntityPath;
            savePath = Path.Combine(savePath, ShareEntityNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Entity.cs");

            if (!RewriteShareEntity && File.Exists(savePath)) return;

            GenFile(ShareEntityTemplatePath, savePath);
        }
        private void ServerEntity()
        {
            string savePath = ServerEntityPath;
            savePath = Path.Combine(savePath, ServerEntityNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Entity.cs");

            if (!RewriteServerEntity && File.Exists(savePath)) return;

            GenFile(ServerEntityTemplatePath, savePath);
        }
        private void ServerDao()
        {
            string savePath = ServerDaoPath;
            savePath = Path.Combine(savePath, ServerDaoNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Dao.cs");

            if (!RewriteServerDao && File.Exists(savePath)) return;

            GenFile(ServerDaoTemplatePath, savePath);
        }
        private void ServerBll()
        {
            string savePath = ServerBllPath;
            savePath = Path.Combine(savePath, ServerBllNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Bll.cs");

            if (!RewriteServerBll && File.Exists(savePath)) return;

            GenFile(ServerBllTemplatePath, savePath);
        }
        private void ServerController()
        {
            string savePath = ServerControllerPath;
            savePath = Path.Combine(savePath, ServerControllerNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Controller.cs");

            if (!RewriteServerController && File.Exists(savePath)) return;

            GenFile(ServerControllerTemplatePath, savePath);
        }
        private void ClientDao()
        {
            string savePath = ClientDaoPath;
            savePath = Path.Combine(savePath, ClientDaoNamespace);
            savePath = Path.Combine(savePath, SonPath, TableInfo.ClassName + "Dal.cs");

            if (!RewriteClientDao && File.Exists(savePath)) return;

            GenFile(ClientDaoTemplatePath, savePath);
        }


        private void GenFile(string templateFileName, string targetFilePath)
        {
            String appStartupPath = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
            appStartupPath = Path.Combine(appStartupPath, "Template", templateFileName);
            appStartupPath = File.ReadAllText(appStartupPath);

            IRazorEngine razorEngine = new RazorEngine();
            IRazorEngineCompiledTemplate template = razorEngine.Compile(appStartupPath);

            //var template = RazorEngineCompiledTemplate.LoadFromFile(appStartupPath);
            var asdf = template.Run(this);

            FileInfo fi = new FileInfo(targetFilePath);

            if (!Directory.Exists(fi.DirectoryName))
            {
                Directory.CreateDirectory(fi.DirectoryName);
            }

            File.WriteAllText(targetFilePath, asdf, Encoding.UTF8);
        }
    }
}
